package com.google.code.swingonfire.utility;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

public enum Country
{

    AFG("AF", "Afghanistan", 4),
    ALA("AX", "\u00c5land", 248),
    ALB("AL", "Albania", 8),
    DZA("DZ", "Algeria", 12),
    ASM("AS", "American Samoa", 16),
    AND("AD", "Andorra", 20),
    AGO("AO", "Angola", 24),
    AIA("AI", "Anguilla", 660),
    ATA("AQ", "Antarctica", 10),
    ATG("AG", "Antigua and Barbuda", 28),
    ARG("AR", "Argentina", 32),
    ARM("AM", "Armenia", 51),
    ABW("AW", "Aruba", 533),
    AUS("AU", "Australia", 36),
    AUT("AT", "Austria", 40),
    AZE("AZ", "Azerbaijan", 31),
    BHS("BS", "Bahamas", 44),
    BHR("BH", "Bahrain", 48),
    BGD("BD", "Bangladesh", 50),
    BRB("BB", "Barbados", 52),
    BLR("BY", "Belarus", 112),
    BEL("BE", "Belgium", 56),
    BLZ("BZ", "Belize", 84),
    BEN("BJ", "Benin", 204),
    BMU("BM", "Bermuda", 60),
    BTN("BT", "Bhutan", 64),
    BOL("BO", "Bolivia", 68),
    BES("BQ", "Bonaire, Sint Eustatius and Saba", 535),
    BIH("BA", "Bosnia and Herzegovina", 70),
    BWA("BW", "Botswana", 72),
    BVT("BV", "Bouvet Island", 74),
    BRA("BR", "Brazil", 76),
    IOT("IO", "British Indian Ocean Territory", 86),
    BRN("BN", "Brunei Darussalam", 96),
    BGR("BG", "Bulgaria", 100),
    BFA("BF", "Burkina Faso", 854),
    BDI("BI", "Burundi", 108),
    KHM("KH", "Cambodia", 116),
    CMR("CM", "Cameroon", 120),
    CAN("CA", "Canada", 124),
    CPV("CV", "Cape Verde", 132),
    CYM("KY", "Cayman Islands", 136),
    CAF("CF", "Central African Republic", 140),
    TCD("TD", "Chad", 148),
    CHL("CL", "Chile", 152),
    CHN("CN", "China", 156),
    CXR("CX", "Christmas Island", 162),
    CCK("CC", "Cocos (Keeling) Islands", 166),
    COL("CO", "Colombia", 170),
    COM("KM", "Comoros", 174),
    COG("CG", "Congo (Brazzaville)", 178),
    COD("CD", "Congo (Kinshasa)", 180),
    COK("CK", "Cook Islands", 184),
    CRI("CR", "Costa Rica", 188),
    CIV("CI", "C\u00f4te d'Ivoire", 384),
    HRV("HR", "Croatia", 191),
    CUB("CU", "Cuba", 192),
    CUW("CW", "Cura\u00e7ao", 531),
    CYP("CY", "Cyprus", 196),
    CZE("CZ", "Czech Republic", 203),
    DNK("DK", "Denmark", 208),
    DJI("DJ", "Djibouti", 262),
    DMA("DM", "Dominica", 212),
    DOM("DO", "Dominican Republic", 214),
    ECU("EC", "Ecuador", 218),
    EGY("EG", "Egypt", 818),
    SLV("SV", "El Salvador", 222),
    GNQ("GQ", "Equatorial Guinea", 226),
    ERI("ER", "Eritrea", 232),
    EST("EE", "Estonia", 233),
    ETH("ET", "Ethiopia", 231),
    FLK("FK", "Falkland Islands", 238),
    FRO("FO", "Faroe Islands", 234),
    FJI("FJ", "Fiji", 242),
    FIN("FI", "Finland", 246),
    FRA("FR", "France", 250),
    GUF("GF", "French Guiana", 254),
    PYF("PF", "French Polynesia", 258),
    ATF("TF", "French Southern Lands", 260),
    GAB("GA", "Gabon", 266),
    GMB("GM", "Gambia", 270),
    GEO("GE", "Georgia", 268),
    DEU("DE", "Germany", 276),
    GHA("GH", "Ghana", 288),
    GIB("GI", "Gibraltar", 292),
    GRC("GR", "Greece", 300),
    GRL("GL", "Greenland", 304),
    GRD("GD", "Grenada", 308),
    GLP("GP", "Guadeloupe", 312),
    GUM("GU", "Guam", 316),
    GTM("GT", "Guatemala", 320),
    GGY("GG", "Guernsey", 831),
    GIN("GN", "Guinea", 324),
    GNB("GW", "Guinea-Bissau", 624),
    GUY("GY", "Guyana", 328),
    HTI("HT", "Haiti", 332),
    HMD("HM", "Heard and McDonald Islands", 334),
    HND("HN", "Honduras", 340),
    HKG("HK", "Hong Kong", 344),
    HUN("HU", "Hungary", 348),
    ISL("IS", "Iceland", 352),
    IND("IN", "India", 356),
    IDN("ID", "Indonesia", 360),
    IRN("IR", "Iran", 364),
    IRQ("IQ", "Iraq", 368),
    IRL("IE", "Ireland", 372),
    IMN("IM", "Isle of Man", 833),
    ISR("IL", "Israel", 376),
    ITA("IT", "Italy", 380),
    JAM("JM", "Jamaica", 388),
    JPN("JP", "Japan", 392),
    JEY("JE", "Jersey", 832),
    JOR("JO", "Jordan", 400),
    KAZ("KZ", "Kazakhstan", 398),
    KEN("KE", "Kenya", 404),
    KIR("KI", "Kiribati", 296),
    PRK("KP", "Korea, North", 408),
    KOR("KR", "Korea, South", 410),
    KWT("KW", "Kuwait", 414),
    KGZ("KG", "Kyrgyzstan", 417),
    LAO("LA", "Laos", 418),
    LVA("LV", "Latvia", 428),
    LBN("LB", "Lebanon", 422),
    LSO("LS", "Lesotho", 426),
    LBR("LR", "Liberia", 430),
    LBY("LY", "Libya", 434),
    LIE("LI", "Liechtenstein", 438),
    LTU("LT", "Lithuania", 440),
    LUX("LU", "Luxembourg", 442),
    MAC("MO", "Macau", 446),
    MKD("MK", "Macedonia", 807),
    MDG("MG", "Madagascar", 450),
    MWI("MW", "Malawi", 454),
    MYS("MY", "Malaysia", 458),
    MDV("MV", "Maldives", 462),
    MLI("ML", "Mali", 466),
    MLT("MT", "Malta", 470),
    MHL("MH", "Marshall Islands", 584),
    MTQ("MQ", "Martinique", 474),
    MRT("MR", "Mauritania", 478),
    MUS("MU", "Mauritius", 480),
    MYT("YT", "Mayotte", 175),
    MEX("MX", "Mexico", 484),
    FSM("FM", "Micronesia", 583),
    MDA("MD", "Moldova", 498),
    MCO("MC", "Monaco", 492),
    MNG("MN", "Mongolia", 496),
    MNE("ME", "Montenegro", 499),
    MSR("MS", "Montserrat", 500),
    MAR("MA", "Morocco", 504),
    MOZ("MZ", "Mozambique", 508),
    MMR("MM", "Myanmar", 104),
    NAM("NA", "Namibia", 516),
    NRU("NR", "Nauru", 520),
    NPL("NP", "Nepal", 524),
    NLD("NL", "Netherlands", 528),
    NCL("NC", "New Caledonia", 540),
    NZL("NZ", "New Zealand", 554),
    NIC("NI", "Nicaragua", 558),
    NER("NE", "Niger", 562),
    NGA("NG", "Nigeria", 566),
    NIU("NU", "Niue", 570),
    NFK("NF", "Norfolk Island", 574),
    MNP("MP", "Northern Mariana Islands", 580),
    NOR("NO", "Norway", 578),
    OMN("OM", "Oman", 512),
    PAK("PK", "Pakistan", 586),
    PLW("PW", "Palau", 585),
    PSE("PS", "Palestine", 275),
    PAN("PA", "Panama", 591),
    PNG("PG", "Papua New Guinea", 598),
    PRY("PY", "Paraguay", 600),
    PER("PE", "Peru", 604),
    PHL("PH", "Philippines", 608),
    PCN("PN", "Pitcairn", 612),
    POL("PL", "Poland", 616),
    PRT("PT", "Portugal", 620),
    PRI("PR", "Puerto Rico", 630),
    QAT("QA", "Qatar", 634),
    REU("RE", "Reunion", 638),
    ROU("RO", "Romania", 642),
    RUS("RU", "Russian Federation", 643),
    RWA("RW", "Rwanda", 646),
    BLM("BL", "Saint Barth\u00e9lemy", 652),
    SHN("SH", "Saint Helena", 654),
    KNA("KN", "Saint Kitts and Nevis", 659),
    LCA("LC", "Saint Lucia", 662),
    MAF("MF", "Saint Martin (French part)", 663),
    SPM("PM", "Saint Pierre and Miquelon", 666),
    VCT("VC", "Saint Vincent and the Grenadines", 670),
    WSM("WS", "Samoa", 882),
    SMR("SM", "San Marino", 674),
    STP("ST", "Sao Tome and Principe", 678),
    SAU("SA", "Saudi Arabia", 682),
    SEN("SN", "Senegal", 686),
    SRB("RS", "Serbia", 688),
    SYC("SC", "Seychelles", 690),
    SLE("SL", "Sierra Leone", 694),
    SGP("SG", "Singapore", 702),
    SXM("SX", "Sint Maarten", 534),
    SVK("SK", "Slovakia", 703),
    SVN("SI", "Slovenia", 705),
    SLB("SB", "Solomon Islands", 90),
    SOM("SO", "Somalia", 706),
    ZAF("ZA", "South Africa", 710),
    SGS("GS", "South Georgia and South Sandwich Islands", 239),
    SSD("SS", "South Sudan", 728),
    ESP("ES", "Spain", 724),
    LKA("LK", "Sri Lanka", 144),
    SDN("SD", "Sudan", 729),
    SUR("SR", "Suriname", 740),
    SJM("SJ", "Svalbard and Jan Mayen Islands", 744),
    SWZ("SZ", "Swaziland", 748),
    SWE("SE", "Sweden", 752),
    CHE("CH", "Switzerland", 756),
    SYR("SY", "Syria", 760),
    TWN("TW", "Taiwan", 158),
    TJK("TJ", "Tajikistan", 762),
    TZA("TZ", "Tanzania", 834),
    THA("TH", "Thailand", 764),
    TLS("TL", "Timor-Leste", 626),
    TGO("TG", "Togo", 768),
    TKL("TK", "Tokelau", 772),
    TON("TO", "Tonga", 776),
    TTO("TT", "Trinidad and Tobago", 780),
    TUN("TN", "Tunisia", 788),
    TUR("TR", "Turkey", 792),
    TKM("TM", "Turkmenistan", 795),
    TCA("TC", "Turks and Caicos Islands", 796),
    TUV("TV", "Tuvalu", 798),
    UGA("UG", "Uganda", 800),
    UKR("UA", "Ukraine", 804),
    ARE("AE", "United Arab Emirates", 784),
    GBR("GB", "United Kingdom", 826),
    UMI("UM", "United States Minor Outlying Islands", 581),
    USA("US", "United States of America", 840),
    URY("UY", "Uruguay", 858),
    UZB("UZ", "Uzbekistan", 860),
    VUT("VU", "Vanuatu", 548),
    VAT("VA", "Vatican City", 336),
    VEN("VE", "Venezuela", 862),
    VNM("VN", "Vietnam", 704),
    VGB("VG", "Virgin Islands, British", 92),
    VIR("VI", "Virgin Islands, U.S.", 850),
    WLF("WF", "Wallis and Futuna Islands", 876),
    ESH("EH", "Western Sahara", 732),
    YEM("YE", "Yemen", 887),
    ZMB("ZM", "Zambia", 894),
    ZWE("ZW", "Zimbabwe", 716);

    public static final String COUNTRY_SYSTEM_PROPERTIES_KEY = "user.country";
    private static final Map<String, Country> COUNTRIES_BY_THREE_LETTER_CODE = new HashMap<String, Country>();
    private static final Map<String, Country> COUNTRIES_BY_TWO_LETTER_CODE = new HashMap<String, Country>();

    private final String twoLetterCode;
    private final String countryName;
    private final Integer countryNumber;

    private Country(String twoLetterCode, String countryName, Integer countryNumber)
    {
        this.twoLetterCode = twoLetterCode;
        this.countryName = countryName;
        this.countryNumber = countryNumber;
    }

    public String getTwoLetterCode()
    {
        return twoLetterCode;
    }

    public String getThreeLetterCode()
    {
        return name();
    }

    public String getCountryName()
    {
        return countryName;
    }

    public Integer getCountryNumber()
    {
        return countryNumber;
    }

    public Locale toLocale()
    {
        // FIXME this is not correct
        return new Locale(getTwoLetterCode().toLowerCase(), getTwoLetterCode().toUpperCase());
    }

    public static Country valueOfThreeLetterCode(String threeLetterCode)
    {
        if (threeLetterCode == null)
        {
            return null;
        }

        if (COUNTRIES_BY_THREE_LETTER_CODE.isEmpty())
        {
            // full synchronization is not yet needed
            synchronized (COUNTRIES_BY_THREE_LETTER_CODE)
            {
                for (Country country : values())
                {
                    COUNTRIES_BY_THREE_LETTER_CODE.put(country.getThreeLetterCode().toLowerCase(), country);
                }
            }
        }

        return COUNTRIES_BY_THREE_LETTER_CODE.get(threeLetterCode.toLowerCase());
    }

    public static Country valueOfTwoLetterCode(String twoLetterCode)
    {
        if (twoLetterCode == null)
        {
            return null;
        }

        if (COUNTRIES_BY_TWO_LETTER_CODE.isEmpty())
        {
            // full synchronization is not yet needed
            synchronized (COUNTRIES_BY_TWO_LETTER_CODE)
            {
                for (Country country : values())
                {
                    COUNTRIES_BY_TWO_LETTER_CODE.put(country.getTwoLetterCode().toLowerCase(), country);
                }
            }
        }

        return COUNTRIES_BY_TWO_LETTER_CODE.get(twoLetterCode.toLowerCase());
    }

    public static Country getDefault()
    {
        String defaultValue = System.getProperty(COUNTRY_SYSTEM_PROPERTIES_KEY);

        if (defaultValue != null)
        {
            Country country = valueOfThreeLetterCode(defaultValue);

            if (country != null)
            {
                return country;
            }

            country = valueOfTwoLetterCode(defaultValue);

            if (country != null)
            {
                return country;
            }
        }

        Locale defaultLocale = Locale.getDefault();

        return valueOfTwoLetterCode(defaultLocale.getCountry());
    }

}